<!--
 * @Author: ShiJunJie
 * @Date: 2021-08-09 09:52:50
 * @LastEditors  : ShiJunJie
 * @LastEditTime : 2022-04-14 17:48:42
 * @Descripttion: 
-->
<template>
  <transition name="slide-fade">
    <div class="slidingVerifyView" v-if="resData" v-show="showType">
      <div
        :style="{
          width: `${resData.background.x}px`
        }"
        @mouseleave="hover = false"
      >
        <div class="tips inHover" :data-placeholder="placeholder || '向右拖动滑块填充拼图'" @mouseenter="hover = true">
          <div
            class="imgs"
            :style="{
              width: `${resData.background.x}px`,
              height: `${resData.background.y}px`
            }"
          >
            <div
              style="position: absolute; background-size: 100% 100%"
              :style="{
                width: `${resData.background.x}px`,
                height: `${resData.background.y}px`,
                background: `url(${resData.background.url})`
              }"
            ></div>
            <div
              :style="{
                zIndex: 2,
                position: 'absolute',
                backgroundSize: '100% 100%',
                left: `${x}px`,
                width: `${resData.slide.x}px`,
                height: `${resData.slide.y}px`,
                background: `url(${resData.slide.url})`
              }"
            ></div>
          </div>

          <div class="trail" :class="dragType" :style="{ width: `${x + 10}px` }"></div>
          <div
            class="drag"
            :class="dragType"
            :style="{
              left: `${x}px`
            }"
            @mousedown="mousedown"
          >
            <svg
              v-if="dragType === 'ok'"
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              aria-hidden="true"
              role="img"
              class="icon iconify iconify--ic"
              preserveAspectRatio="xMidYMid meet"
              viewBox="0 0 24 24"
            >
              <path d="M9 16.17L4.83 12l-1.42 1.41L9 19L21 7l-1.41-1.41z"></path>
            </svg>
            <svg
              v-else-if="dragType === 'error'"
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              aria-hidden="true"
              role="img"
              class="icon iconify iconify--ic"
              preserveAspectRatio="xMidYMid meet"
              viewBox="0 0 24 24"
            >
              <path d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z"></path>
            </svg>
            <svg
              v-else
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              aria-hidden="true"
              role="img"
              class="icon iconify iconify--ic"
              preserveAspectRatio="xMidYMid meet"
              viewBox="0 0 24 24"
            >
              <path d="M16.01 11H4v2h12.01v3L20 12l-3.99-4z"></path>
            </svg>
          </div>
        </div>
        <div class="slide-bottom">
          <div></div>
          <div class="reload">
            <div @click.stop="showType = false">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                xmlns:xlink="http://www.w3.org/1999/xlink"
                aria-hidden="true"
                role="img"
                class="icon iconify iconify--ri"
                preserveAspectRatio="xMidYMid meet"
                viewBox="0 0 24 24"
              >
                <path
                  d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10s-4.477 10-10 10zm0-2a8 8 0 1 0 0-16a8 8 0 0 0 0 16zm0-9.414l2.828-2.829l1.415 1.415L13.414 12l2.829 2.828l-1.415 1.415L12 13.414l-2.828 2.829l-1.415-1.415L10.586 12L7.757 9.172l1.415-1.415L12 10.586z"
                ></path>
              </svg>
            </div>
            <div @click.stop="init">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                xmlns:xlink="http://www.w3.org/1999/xlink"
                aria-hidden="true"
                role="img"
                class="icon iconify iconify--ri"
                preserveAspectRatio="xMidYMid meet"
                viewBox="0 0 24 24"
              >
                <path
                  d="M5.463 4.433A9.961 9.961 0 0 1 12 2c5.523 0 10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3A8 8 0 0 0 6.46 6.228l-.997-1.795zm13.074 15.134A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12c0-2.136.67-4.116 1.81-5.74L7 12H4a8 8 0 0 0 13.54 5.772l.997 1.795z"
                ></path>
              </svg>
            </div>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import verify from './verify';

export type slodeConfig = {
  errorNum: Number;
  showType: String | Boolean;
};

const props = defineProps<{
  placeholder?: String;
  config?: slodeConfig;
}>();

const emit = defineEmits({ onCallback: (data: any) => {} });
// 滑块x坐标
const x = ref(0);
// 偏移量
const offset = ref(0);
// 鼠标按下状态
const down = ref(false);
// 接口请求状态
const postType = ref(false);
// 组件显示状态
const showType = ref(true);
// 滑动轨迹
const positionArray = ref([]);
const hover = ref(false);
// 移动状态
const dragType = ref('');
// 触点回退
let setIntervalVal: NodeJS.Timeout = null;
// 初始化参数
const resData = ref();
// 错误次数
const errorCount = ref(0);

// 组件配置项
let defaultConfig = {
  // 错误刷新次数
  errorNum: 3,
  // 组件默认展示样式
  showType: 'alert',
  // 组件配置项覆盖
  ...props.config
};

const show = () => (showType.value = true);
const hide = () => ((showType.value = false), (resData.value = ''));

let dataId: any = null;
// HACK: 自定义接口
const init = async (id: any = '') => {
  showType.value = true;
  !dataId ? (dataId = id) : '';
  // HACK: 验证码初始化参数
  let res: any = await verify.get(dataId);

  if (!res.code) {
    resData.value = res.data;
    console.log('加载完毕数据为:', resData.value);
  }

  x.value = 0;
  offset.value = 0;
  down.value = false;
  dragType.value = '';
};

// 鼠标开始滑动
const mousedown = (mousedown_event: any) => {
  if (down.value || dragType.value) return false;
  down.value = true;
  offset.value = mousedown_event.x - x.value;
  dragType.value = 'move';

  mousedown_event = mousedown_event || window.event;
  if (mousedown_event.preventDefault) {
    mousedown_event.preventDefault();
  } else {
    mousedown_event.returnValue = false;
  }
  document.onmousemove = function (ev: any) {
    let _event = ev || window.event;
    if (down.value) {
      x.value = Math.min(Math.max(0, _event.x - offset.value), resData.value.background.x - resData.value.slide.x);
      positionArray.value.push({
        position: _event.clientX,
        // y: _event.clientY,
        time: new Date().getTime()
      });
    }
  };
  document.onmouseup = mouseup;
  return true;
};

// 鼠标滑动抬起
const mouseup = async () => {
  if (down.value || dragType.value) {
    down.value = false;
    document.onmousemove = null;
    // HACK: 验证码提交参数123
    const res: any = await verify.post({
      id: dataId,
      lastPosition: x.value,
      imageToken: resData.value.imageToken,
      startTime: positionArray.value[0]?.time,
      endTime: positionArray.value[positionArray.value.length - 1]?.time,
      positions: toRaw(positionArray.value)
    });
    if (!res.code) {
      reInit('ok');
      emit('onCallback', res);
    } else {
      reInit('error');
    }
  }
  document.onmouseup = () => {};
};

// 提交回调
const reInit = (_dragType: 'ok' | 'error') => {
  if (_dragType !== 'ok') {
    dragType.value = 'error';
    errorCount.value++;
    setTimeout(() => {
      // 错误达到指定次数重新拉取图片
      errorCount.value >= defaultConfig.errorNum ? (init(), (errorCount.value = 0)) : '';
      // 回退动画
      setIntervalVal = setInterval(() => {
        if (x.value > 0) {
          x.value = x.value - resData.value.background.x / 40;
        } else {
          x.value = 0;
          dragType.value = '';
          clearInterval(setIntervalVal);
          setIntervalVal = null;
        }
      }, 1);
    }, 500);
    positionArray.value = [];
  } else {
    dragType.value = 'ok';
    setTimeout(() => {
      hide();
    }, 800);
  }
};

// 对外暴漏的方法
defineExpose({ reInit, init, show, hide });
</script>

<style lang="scss">
@import url('./Verify.scss');
</style>
